﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Cloak.Globalization;
using Ruleweaver.Rules.CheckMethods;
using Ruleweaver.Conditions;
using Ruleweaver.Rules;

namespace Ruleweaver.Annotation
{
	[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)]
	[ContractClass(typeof(CheckAttributeContract))]
	public abstract class CheckAttribute : Attribute, IConditionDeclaration
	{
		#region IConditionDeclaration

		public IEnumerable<Condition> GetConditions(Type targetType)
		{
			Rule rule = GetCheckMethod().GetRule(targetType);

			if(Negate)
			{
				rule = Rule.Not(rule);
			}

			return GetConditions(rule, targetType);
		}
		#endregion

		public string Conditions { get; set; }

		public bool Negate { get; set; }

		protected abstract ICheckMethod GetCheckMethod();

		private IEnumerable<Condition> GetConditions(Rule rule, Type targetType)
		{
			if(Conditions == null)
			{
				yield return new Condition(rule, targetType);
			}
			else
			{
				foreach(var conditionName in Conditions.Split(',').Distinct())
				{
					yield return new Condition(rule, targetType, conditionName);
				}
			}
		}
	}

	[ContractClassFor(typeof(CheckAttribute))]
	internal abstract class CheckAttributeContract : CheckAttribute
	{
		protected override ICheckMethod GetCheckMethod()
		{
			Contract.Ensures(Contract.Result<ICheckMethod>() != null);

			return null;
		}
	}
}